﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.XPath;
using System.Text;
using Engine.Dtd.Schema;
using System.IO;
using System.Reflection;
using System.Xml;
using System.Diagnostics;
using Engine.Sgml.Validation;

namespace Engine.Sgml.XPath {
    class SgmlNavigator : XPathNavigator {
        SElement root;
        SElement element;
        SAttribute attribute;
        SObject node;

        internal SgmlNavigator(SElement root) {
            this.root = root;
            this.element = root;
            this.node = element;
            }

        internal SElement Root {
            get { return root; }
            set {
                Guard.ArgumentNotNull(value, "value");
                root = value;
                element = root;
                node = element;
                }
            }

        internal SElement UnderlyingElement {
            get { return element; }
            }

        internal SAttribute UnderlyingAttribute {
            get { return attribute; }
            }

        public override object UnderlyingObject {
            get { return node; }
            }

        public override string BaseURI {
            get { return string.Empty; }
            }

        public override XPathNavigator Clone() {
            SgmlNavigator clone = new SgmlNavigator(root);
            clone.element = element;
            clone.node = node;
            clone.attribute = attribute;
            return clone;
            }

        public override bool HasAttributes {
            get { return element.HasAttributes; }
            }

        public override bool HasChildren {
            get { return element.HasElements; }
            }

        public override bool IsEmptyElement {
            get { return element.IsEmpty; }
            }

        public override bool IsSamePosition(XPathNavigator other) {
            SgmlNavigator navigator = other as SgmlNavigator;
            if (navigator == null)
                return false;
            return navigator.node == node;
            }

        public override bool MoveTo(XPathNavigator other) {
            SgmlNavigator navigator = other as SgmlNavigator;
            if (navigator == null)
                return false;
            root = navigator.root;
            element = navigator.element;
            node = navigator.node;
            attribute = navigator.attribute;
            return true;
            }

        public override bool MoveToFirstAttribute() {
            if (element.HasAttributes) {
                attribute = element.Attributes.FirstElement;
                node = attribute;
                return true;
                }
            else
                return false;
            }

        public override bool MoveToNextAttribute() {
            if (!attribute.HasNextAttribute())
                return false;
            attribute = attribute.NextAttribute;
            node = attribute;
            return true;
            }

        public override bool MoveToFirstChild() {
            if (element.HasElements) {
                element = element.Nodes.FirstElement;
                node = element;
                return true;
                }
            else
                return false;
            }

        public override bool MoveToFirstNamespace(XPathNamespaceScope namespaceScope) {
            return false;
            }

        public override bool MoveToId(string id) {
            throw new NotSupportedException();
            }

        public override bool MoveToNext() {
            if (element.NextNode == null || element == root)
                return false;
            else {
                element = element.NextNode;
                node = element;
                return true;
                }
            }

        public override bool MoveToNextNamespace(XPathNamespaceScope namespaceScope) {
            return false;
            }

        public override bool MoveToParent() {
            if (node.Parent == null || node == root)
                return false;
            element = node.Parent;
            node = element;
            return true;
            }

        public override bool MoveToPrevious() {
            if (element.PreviousNode == null || element == root)
                return false;
            element = element.PreviousNode;
            node = element;
            return true;
            }

        public override XmlNameTable NameTable {
            get {
                return SName.NameTable;
                }
            }

        public override string NamespaceURI {
            get { return SName.EmptyString; }
            }

        public override XPathNodeType NodeType {
            get {
                switch (node.NodeType) {
                    case SgmlNodeType.Attribute:
                        return XPathNodeType.Attribute;
                    case SgmlNodeType.CData:
                    case SgmlNodeType.CDataSection:
                        return XPathNodeType.Text;
                    case SgmlNodeType.Comment:
                        return XPathNodeType.Comment;
                    case SgmlNodeType.Document:
                        return XPathNodeType.Root;
                    case SgmlNodeType.DocumentType:
                        return XPathNodeType.All;
                    case SgmlNodeType.Condition:
                    case SgmlNodeType.Element:
                        if (node == root)
                            return XPathNodeType.Root;
                        else
                            return XPathNodeType.Element;
                    case SgmlNodeType.EndElement:
                        return XPathNodeType.Element;
                    case SgmlNodeType.None:
                        return XPathNodeType.All;
                    case SgmlNodeType.Text:
                        return XPathNodeType.Text;
                    case SgmlNodeType.SignificantWhiteSpace:
                        return XPathNodeType.SignificantWhitespace;
                    case SgmlNodeType.WhiteSpace:
                        return XPathNodeType.Whitespace;
                    default:
                        return XPathNodeType.All;
                    }
                }
            }

        public override string Name {
            get { return node.Name.ToString(); }
            }

        public override string LocalName {
            get { return node.LocalName; }
            }

        public override string Prefix {
            get { return node.Prefix; }
            }

        public override string Value {
            get { return node.Value; }
            }
        }
    }
